# -*- coding: utf-8 -*-
"""
数据清洗模块 - 任务1.3.1
负责对爬取的数据进行清洗、验证和标准化处理
"""

import re
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
from urllib.parse import urljoin, urlparse


class DataCleaner:
    """数据清洗器"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.base_url = "https://sz.pupuwang.com"
    
    def clean_data_batch(self, data_list: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """批量清洗数据"""
        cleaned_data = []
        
        for i, data in enumerate(data_list):
            try:
                cleaned_item = self.clean_single_data(data)
                if cleaned_item:
                    cleaned_data.append(cleaned_item)
                    self.logger.debug(f"清洗第 {i+1} 条数据成功")
                else:
                    self.logger.warning(f"第 {i+1} 条数据清洗后无效，已跳过")
            except Exception as e:
                self.logger.error(f"清洗第 {i+1} 条数据失败: {e}")
                continue
        
        self.logger.info(f"批量清洗完成，输入 {len(data_list)} 条，输出 {len(cleaned_data)} 条")
        return cleaned_data
    
    def clean_single_data(self, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """清洗单条数据"""
        if not data:
            return None
        
        cleaned_data = {}
        
        # 清洗标题
        cleaned_data['title'] = self._clean_title(data.get('title', ''))
        
        # 清洗联系人
        cleaned_data['contact_person'] = self._clean_contact_person(data.get('contact_person', ''))
        
        # 清洗联系方式
        cleaned_data['contact_info'] = self._clean_contact_info(data.get('contact_info', ''))
        
        # 清洗业态信息
        cleaned_data['business_type'] = self._clean_business_type(data.get('business_type', ''))
        
        # 清洗区域信息
        cleaned_data['area_info'] = self._clean_area_info(data.get('area_info', ''))
        
        # 清洗建筑面积
        cleaned_data['building_area'] = self._clean_building_area(data.get('building_area', ''))
        
        # 清洗租金信息
        cleaned_data['acceptable_rent'] = self._clean_rent_info(data.get('acceptable_rent', ''))
        
        # 清洗发布时间
        publish_time = self._clean_publish_time(data.get('publish_time'))
        if not publish_time or not self._is_within_month(publish_time):
            return None  # 无效时间或超过一个月的数据
        cleaned_data['publish_time'] = publish_time
        
        # 清洗详情页URL
        cleaned_data['detail_url'] = self._clean_detail_url(data.get('detail_url', ''))
        
        # 保留其他字段
        cleaned_data['city'] = data.get('city', '深圳')
        cleaned_data['data_source'] = data.get('data_source', 'pupuwang')
        
        # 验证数据完整性
        if not self._validate_data_completeness(cleaned_data):
            return None
        
        return cleaned_data
    
    def _clean_title(self, title: str) -> str:
        """清洗标题"""
        if not title:
            return ""
        
        # 移除多余空白字符
        title = re.sub(r'\s+', ' ', title.strip())
        
        # 移除特殊字符
        title = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s\-\+\(\)（）]', '', title)
        
        return title[:100]  # 限制长度
    
    def _clean_contact_person(self, contact: str) -> str:
        """清洗联系人信息"""
        if not contact:
            return ""
        
        # 移除空白字符
        contact = contact.strip()
        
        # 移除括号内容和称谓
        contact = re.sub(r'[（(][^）)]*[）)]', '', contact)
        contact = re.sub(r'先生|女士|小姐', '', contact)
        
        # 移除数字和特殊字符
        contact = re.sub(r'[0-9\W]', '', contact)
        
        # 验证是否为有效姓名
        if len(contact) < 1 or len(contact) > 10:
            return ""
        
        return contact
    
    def _clean_contact_info(self, contact_info: str) -> str:
        """清洗联系方式"""
        if not contact_info:
            return ""
        
        # 提取手机号码
        phone_pattern = r'1[3-9]\d{9}'
        match = re.search(phone_pattern, contact_info)
        
        if match:
            return match.group(0)
        
        # 如果没有找到标准手机号，保留原始信息（可能是座机）
        contact_info = re.sub(r'\s+', '', contact_info.strip())
        return contact_info[:20]  # 限制长度
    
    def _clean_business_type(self, business_type: str) -> str:
        """清洗业态信息"""
        if not business_type:
            return ""
        
        # 移除多余空白
        business_type = business_type.strip()
        
        # 标准化业态名称
        business_mapping = {
            '餐饮': '餐饮',
            '餐饮美食': '餐饮',
            '快餐店': '餐饮',
            '餐厅': '餐饮',
            '零售': '零售',
            '百货超市': '零售',
            '超市': '零售',
            '便利店': '零售',
            '娱乐': '娱乐',
            '休闲娱乐': '娱乐',
            'KTV': '娱乐',
            '网吧': '娱乐',
            '冷饮甜品店': '餐饮',
            '冷饮甜品': '餐饮'
        }
        
        for key, value in business_mapping.items():
            if key in business_type:
                return value
        
        return business_type[:20]  # 限制长度
    
    def _clean_area_info(self, area_info: str) -> str:
        """清洗区域信息"""
        if not area_info:
            return ""
        
        # 移除多余空白
        area_info = area_info.strip()
        
        # 移除可能的前缀
        area_info = re.sub(r'^考虑区域[：:]?\s*', '', area_info)
        
        return area_info[:50]  # 限制长度
    
    def _clean_building_area(self, building_area: str) -> str:
        """清洗建筑面积"""
        if not building_area:
            return ""
        
        # 提取数字和单位
        area_pattern = r'(\d+[-~–—]\d+|\d+)\s*平米?'
        match = re.search(area_pattern, str(building_area))
        
        if match:
            area_value = match.group(1)
            return f"{area_value}平米"
        
        return str(building_area).strip()[:20]
    
    def _clean_rent_info(self, rent_info: str) -> str:
        """清洗租金信息"""
        if not rent_info:
            return "面议"
        
        rent_info = rent_info.strip()
        
        # 如果已经是标准格式，直接返回
        if "面议" in rent_info:
            return "面议"
        
        # 标准化租金格式
        patterns = [
            r'(\d+[-~–—]\d+)元/月',
            r'(\d+[-~–—]\d+)万/月',
            r'(\d+)元/月',
            r'(\d+)万/月'
        ]
        
        for pattern in patterns:
            match = re.search(pattern, rent_info)
            if match:
                return match.group(0)
        
        # 如果包含数字，尝试提取
        number_match = re.search(r'\d+[-~–—]\d+|\d+', rent_info)
        if number_match:
            return f"{number_match.group(0)}元/月"
        
        return "面议"
    
    def _clean_publish_time(self, publish_time) -> Optional[datetime]:
        """清洗发布时间"""
        if not publish_time:
            return None
        
        if isinstance(publish_time, datetime):
            return publish_time
        
        if isinstance(publish_time, str):
            try:
                return datetime.strptime(publish_time, '%Y-%m-%d %H:%M:%S')
            except ValueError:
                try:
                    return datetime.strptime(publish_time, '%Y-%m-%d')
                except ValueError:
                    return None
        
        return None
    
    def _clean_detail_url(self, detail_url: str) -> str:
        """清洗详情页URL"""
        if not detail_url:
            return ""
        
        detail_url = detail_url.strip()
        
        # 如果已经是完整URL，直接返回
        if detail_url.startswith('http'):
            return detail_url
        
        # 如果是相对路径，添加域名前缀
        if detail_url.startswith('/'):
            return urljoin(self.base_url, detail_url)
        
        return detail_url
    
    def _is_within_month(self, publish_time: datetime) -> bool:
        """检查发布时间是否在一个月内"""
        if not publish_time:
            return False
        
        now = datetime.now()
        one_month_ago = now - timedelta(days=30)
        return publish_time >= one_month_ago
    
    def _validate_data_completeness(self, data: Dict[str, Any]) -> bool:
        """验证数据完整性"""
        # 必须有标题或联系人或业态信息之一
        if not any([
            data.get('title'),
            data.get('contact_person'),
            data.get('business_type')
        ]):
            return False
        
        # 必须有发布时间
        if not data.get('publish_time'):
            return False
        
        return True
